﻿@page "/chatroom"

@inject NavigationManager navigationManager
@using BlazorApp4.Data;
@using Microsoft.AspNetCore.SignalR.Client
@using System.ComponentModel.DataAnnotations
@inject IWebHostEnvironment Environment
@inject Blazored.LocalStorage.ILocalStorageService localStorage
@inject IJSRuntime JS
@using Microsoft.Extensions.Logging;
@using Microsoft.JSInterop;
@using System.Net.Mail;
@using System.Net.Mime;
@using System.Net;
@using System.Timers;
@inject DaprClient daprClient;
@using Microsoft.AspNetCore.Components.Server.Circuits
@using System.Text;
@inject CircuitHandler CircuitHandlerService
@implements IDisposable


<audio controls="controls" @ref="notificationAudio" src="audio/notification.wav" style="display:none;">
	您的浏览器不支持audio元素
</audio>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-4  col-sm-12 @userListStyle" style="background:pink">     
            <ul class="list-group" id="user_list">

                <!--注意onclick的写法-->
                <div class="d-flex w-100 justify-content-between" @onclick="@(() => startChatHall())">大厅</div>
                <p>@_latestMessage</p>
				<hr/>
                @foreach (var item in _recentUsers)
                {
                    @if (item.Username != _username){
						<div class="d-flex w-100 justify-content-between" @onclick="@(() => StartChatWithSpecificUser(@item.Username, ""))">
							<h5 class="mb-1">@item.Username</h5>
							@if (@item.Counter != 0) {
								<span class="badge bg-primary rounded-pill">@item.Counter</span>
							}
						</div>
						<p class="mb-1">@item.LatestMessage</p>
						<hr/>
                    }

                }
            </ul>
        </div>
        <div class="col-md-8 col-sm-12 @messagelistStyle">
            @if (!_isSpecific)
            {
                @if (!_isChatting)
                {
                    <p>
                        输入您的名字开始聊天:
                    </p>

                    <input type="text" maxlength="32" @bind="@_username" />
                    <button type="button" @onclick="@(()=> Chat("button"))"><span class="oi oi-chat" aria-hidden="true"></span> 开始畅聊!</button>

                    // Error messages
                    @if (_message != null)
                    {
                        <div class="invalid-feedback">@_message</div>
                        <small id="emailHelp" class="form-text text-muted">@_message</small>
                    }
                }
                else
                {
                    // banner to show current user
                    <div class="alert alert-secondary mt-4" role="alert">
                        <span class="oi oi-person mr-2" aria-hidden="true"></span>
                        <span>欢迎<b>@_username</b>加入聊天室</span>
                        <button class="btn btn-sm btn-warning ml-md-auto" @onclick="@DisconnectAsync">断开连接</button>
						<button class="btn btn-sm btn-info ml-md-auto return-user-list" @onclick="@backUserList">返回</button>
						
                    </div>

                    @*display messages*@
                    <div @ref="scrollElement" id="hallChat">
                        @foreach (var item in _messages)
                        {
                            @if (item.IsNotice)
                            {
                                <div class="alert alert-info">@item.Body</div>
                            }
                            else
                            {
                                <div class="@item.CSS">
                                    <div class="user" @onclick="@(() => StartChatWithSpecificUser(@item.Username, "我是" + @_username + ",很高兴认识你"))">@item.Username</div>
                                    @if (@item.Body.Contains("files/"))
                                    {
                                        <span class="btn btn-link" @onclick="@(() => DownloadFileFromURL(@item.Body))">
                                            @Path.GetFileName(@item.Body)
                                        </span>
                                    } 
                                    else{
                                        <div class="msg">@item.Body</div>
                                    }

                                    @if (@item.Body.Contains("files/img/"))
                                    {
                                        <img src="@item.Body" style="width:60%; height:60%">

                                    }
                                    
                                </div>
                            }
                        }
                    </div>
					
					<div class="fix-input">
					    <hr />
                        <input type="text" @bind-value="_newMessage" @bind-value:event="oninput" @onkeydown="WatchInputValue" />

                        <button class="btn btn-default" @onclick="@(() => SendAsync(_newMessage))">发送</button>

                        <InputFile OnChange="@LoadFile"  multiple/>

					</div>
                }
            }   
            else
            {
				// banner to show current user
				<div class="alert alert-secondary mt-4" role="alert">
				    <span class="oi oi-person mr-2" aria-hidden="true"></span>
				    <span>您正在和<b>@specific_user</b>聊天</span>
					<button class="btn btn-sm btn-info ml-md-auto return-user-list" @onclick="@backUserList">返回</button>
				</div>
                @*display messages*@
                <!--单独聊天部分的消息处理-->
                <div @ref="scrollSpecificElement" id="specificChat">
                    @foreach (var item in _specoficMessages)
                    {
                        @if (item.IsNotice)
                        {
                            <div class="alert alert-info">@item.Body</div>
                        }
                        else
                        {
                            <div class="@item.CSS">
                                <div class="user">@item.Username</div>
                                @if (@item.Body.Contains("files/"))
                                {
                                    <span class="btn btn-link" @onclick="@(() => DownloadFileFromURL(@item.Body))">
                                            @Path.GetFileName(@item.Body)
                                    </span>
                                }
                                else
                                {
                                    <div class="msg">@item.Body</div>
                                }

                                @if (@item.Body.Contains("files/img/"))
                                {
                                    <img src="@item.Body" style="width:60%; height:60%">
                                }
                            </div>
                        }
                    }
				</div>
				<div class="fix-input">
					<hr />
                    <input type="text" @bind-value="_newMessage" @bind-value:event="oninput" @onkeydown="WatchInputValue" />

					<button class="btn btn-default" @onclick="@(() => StartChatWithSpecificUser(specific_user, _newMessage))">发送</button>
                    <InputFile OnChange="@LoadFile" multiple />
				</div>
            }
        </div>
    </div>
</div>




@code {
    //可以通过list-group-item-success来控制是否点击
    long maxAllowedSize = 102400000;
    private Timer timer;
    // 考虑以后用 可能会用来操作DOM元素
    private ElementReference scrollElement;
    private ElementReference scrollSpecificElement;
    private ElementReference notificationAudio;
    // flag to indicate chat status
    private bool _isChatting = false;
    private bool _isSpecific = false;

    // name of the user who will be chatting
    private string _username = String.Empty;

    // on-screen message
    private string _message = String.Empty;

    // new message input
    private string _newMessage = String.Empty;

    // list of messages in chat
    private List<Message> _messages = new List<Message>();
    private List<Message> _specoficMessages = new List<Message>();

    private List<String> _users = new List<String>();

    private string _hubUrl = String.Empty;
    private HubConnection _hubConnection;

    private List<RecentUser> _recentUsers = new List<RecentUser>();

    private string specific_user = String.Empty;

    private string _latestMessage = String.Empty;

    string _fileErrorMessage = String.Empty;


    //这个测试发现不能该 听神奇的呀   和配置文件有關
    const string DAPR_STATE_STORE = "statestore";

    const string USERS_KEY = "userskey";
    private string scroll_id = String.Empty;
    private string _deviceType = String.Empty;
    //在小屏幕设备上设置显示和隐藏
    private string userListStyle = String.Empty;
    private string messagelistStyle = String.Empty;
    protected override async Task  OnInitializedAsync()
    {
        _isSpecific = false;
        //session可以用来判断是否离开页面 单blazor server用不了
        // await ProtectedSessionStore.SetAsync("leavePage", "initPage");
        //获取设备类型
        _deviceType= await JS.InvokeAsync<String>("getDeviceType");
        Console.WriteLine("deviceType:" + _deviceType);
        _username = await localStorage.GetItemAsStringAsync("chat_username");
        await init();
        Console.WriteLine("_username init:" + _username);
        await base.OnInitializedAsync();
    }


    private async Task DownloadFileFromURL(string  file)
    {
        var uri = navigationManager.BaseUri;
        await JS.InvokeVoidAsync("triggerFileDownloadViaPath", file, uri);
    }

    private async Task LoadFile(InputFileChangeEventArgs e)
    {

        var files = e.GetMultipleFiles(10);
        foreach (var file in files)
        {
            try
            {
                var trustedFileName = file.Name;
                using (var stream = file.OpenReadStream(maxAllowedSize))
                {

                    Console.WriteLine("enter LoadFile");
                    byte[] buffer = new byte[stream.Length];
                    await stream.ReadAsync(buffer, 0, buffer.Length);
                    //传输stream会出现序列化错误
                    /*
                    * == APP ==    at System.IO.Stream.get_ReadTimeout()
                    == APP ==    at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
                    == APP ==    at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
                    == APP ==    at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
                    == APP ==    at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
                    == APP ==    at System.Text.Json.Serialization.JsonConverter`1.WriteCoreAsObject(Utf8JsonWriter writer, Object value, JsonSerializerOptions options, WriteStack& state)
                    == APP ==    at System.Text.Json.JsonSerializer.WriteUsingSerializer[TValue](Utf8JsonWriter writer, TValue& value, JsonTypeInfo jsonTypeInfo)
                    == APP ==    at System.Text.Json.JsonSerializer.Serialize(Utf8JsonWriter writer, Object value, Type inputType, JsonSerializerOptions options)
                    == APP ==    at Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.WriteArguments(Object[] arguments, Utf8JsonWriter writer)
                    == APP ==    at Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.WriteInvocationMessage(InvocationMessage message, Utf8JsonWriter writer)
                    == APP ==    at Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.WriteMessageCore(HubMessage message, IBufferWriter`1 stream)
                    == APP ==    at Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.WriteMessage(HubMessage message, IBufferWriter`1 output)
                    == APP ==    at Microsoft.AspNetCore.SignalR.Client.HubConnection.SendHubMessage(ConnectionState connectionState, HubMessage hubMessage, CancellationToken cancellationToken)
                    == APP ==    at Microsoft.AspNetCore.SignalR.Client.HubConnection.SendCoreAsyncCore(String methodName, Object[] args, CancellationToken cancellationToken)
                    == APP ==    at System.Threading.Tasks.ForceAsyncAwaiter.GetResult()
                    == APP ==    at Microsoft.AspNetCore.SignalR.Client.HubConnection.SendCoreAsync(String methodName, Object[] args, CancellationToken cancellationToken)
                    == APP ==    at BlazorApp4.Pages.ChatRoom.LoadFile(InputFileChangeEventArgs e) in C:\Users\tengyanbo\source\blazor-bug-for41469\Pages\ChatRoom.razor:line 231
                    */
                    if (specific_user == String.Empty || specific_user == "")
                    {
                        await _hubConnection.SendAsync("UploadFile", _username, file.Name, buffer);                        
                    } else
                    {
                        @* _specoficMessages = await daprClient.GetStateAsync<List<Message>>(DAPR_STATE_STORE, _username + "_spec_" + specific_user);
                        if (_specoficMessages == null)
                        {
                            _specoficMessages = new List<Message>();
                        }
                        var newMessage = trustedFileName;
                        Console.WriteLine("why not here" + newMessage);
                        var result = _recentUsers.Find(recentUser => recentUser.Username == specific_user);
                        if (result == null)
                        {
                            RecentUser recentUser = new RecentUser(specific_user, 0, newMessage);
                            _recentUsers.Add(recentUser);
                        }
                        else
                        {
                            //更新最新的消息
                            foreach (var recent_user in _recentUsers)
                            {
                                if (recent_user.Username == specific_user)
                                {
                                    recent_user.LatestMessage = newMessage;
                                }
                            }

                        }
                        await daprClient.SaveStateAsync(DAPR_STATE_STORE, _username + "_recent_users", _recentUsers);
                        var specific_message = new Message(_username, newMessage, true);
                        _specoficMessages.Add(specific_message); 
                        await daprClient.SaveStateAsync(DAPR_STATE_STORE, _username + "_spec_" + specific_user, _specoficMessages);*@
                        //文件处理需要双方都在线
                        await _hubConnection.SendAsync("UploadFile2Spec", _username, specific_user, file.Name, buffer);
                    }
                }
                // 创建一个 Stream 对象
                //MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes("Hello, world!"));

                // 将 Stream 对象传递给 SignalR Hub

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }
        }
        Console.WriteLine("Finish load");  
    }


    private async Task init() {
        //存储所有的用户  通配符不行的呀
        _users = await daprClient.GetStateAsync<List<String>>(DAPR_STATE_STORE, USERS_KEY);
        if (_users == null)
        {
            _users = new List<string>();

        }
        if (_username != String.Empty && _username != null && _username != "")
        {
            _messages = await daprClient.GetStateAsync<List<Message>>(DAPR_STATE_STORE, _username);
            if (_messages == null)
            {
                _messages = new List<Message>();
            }
            //使用姓名 + _recent_users做为键
            _recentUsers = await daprClient.GetStateAsync<List<RecentUser>>(DAPR_STATE_STORE, _username + "_recent_users");
            if (_recentUsers == null)
            {
                _recentUsers = new List<RecentUser>();
            }
            await Chat("init");
        } else {
            messagelistStyle = "messagelistShow";
            userListStyle = "userListHide";
        }
    }

    protected override async Task OnAfterRenderAsync(bool isFirst)
    {
        if (isFirst)
        { 
            Console.WriteLine("first render" + _username);
        }
        await base.OnAfterRenderAsync(isFirst);
        //DOM操作需要在这里进行，否则会出现dom未加载完成的情况
        await JS.InvokeVoidAsync("scrollBottom", scroll_id);
    }

    public async Task Chat(String init)
    {
        if (init != "init") {
            // check username is valid
            if (string.IsNullOrWhiteSpace(_username))
            {
                messagelistStyle = "messagelistShow";
                userListStyle = "userListHide";
                _message = "请输入一个名字";
                return;
            };
            messagelistStyle = "messagelistHide";
            userListStyle = "userListShow";
            string name = await localStorage.GetItemAsStringAsync("chat_username");
            if (_users.Contains(_username))
            {
                _message = "当前名字已经被使用，请请输入其他的名字";
                return;

            }
            if (name == null)
            {
                await localStorage.SetItemAsStringAsync("chat_username", _username);
                _users.Add(_username);
                await daprClient.SaveStateAsync(DAPR_STATE_STORE, USERS_KEY, _users);
            }
            if (_username != String.Empty && _username != null && _username != "")
            {
                _messages = await daprClient.GetStateAsync<List<Message>>(DAPR_STATE_STORE, _username);
                if (_messages == null)
                {
                    _messages = new List<Message>();
                }
                //使用姓名 + _recent_users做为键
                _recentUsers = await daprClient.GetStateAsync<List<RecentUser>>(DAPR_STATE_STORE, _username + "_recent_users");
                if (_recentUsers == null)
                {
                    _recentUsers = new List<RecentUser>();
                }
            }
        }

        messagelistStyle = "messagelistHide";
        userListStyle = "userListShow";
        try
        {
            // Start chatting and force refresh UI.
            _isChatting = true;
            await Task.Delay(1);

            // Create the chat client
            string baseUrl = navigationManager.BaseUri;

            _hubUrl = baseUrl.TrimEnd('/') + BlazorChatHub.HubUrl;

            _hubConnection = new HubConnectionBuilder()
                .WithUrl(_hubUrl)
                .Build();

            _hubConnection.On<string, string>("Broadcast", BroadcastMessage);
            _hubConnection.On<long>("ReceiveProgress", progress =>
           {
               Console.WriteLine(progress);
           });

            _hubConnection.On<byte[]>("ReceiveFile", byteArray =>
           {
               Console.WriteLine(byteArray);
           }); 
            _hubConnection.On<string,string, string>("BroadcastSelf", BroadcastSelf);


            await _hubConnection.StartAsync();
            //为了再次连接的时候，在服务端获取connectionID
            await SendAsync($"[Notice] {_username} 加入聊天室");
        }
        catch (Exception e)
        {
            Console.WriteLine("Why not here 666" + _username);
            _message = $"ERROR: Failed to start chat client: {e.Message}";
            _isChatting = false;
        }
        InitTimer();
    }

    private void InitTimer()
    {
        timer = new Timer(1000);
        timer.Elapsed += UpdateCurrentTime;
        timer.Start();
    }

    private async  void UpdateCurrentTime(object sender, ElapsedEventArgs e)
    {
        var currentTime = DateTime.Now.ToString("HH:mm:ss");
        // var result = await ProtectedSessionStore.GetAsync<string>("leavePage");

        if (_hubConnection != null)
        {
            if (_hubConnection.State == HubConnectionState.Connected)
            {
                ;
            } else
            {
                Console.WriteLine("当前是非连接状态" + _hubConnection.State);    
            }
        }
    }

    private async Task ShowNotification(string title, string message)
    {
        try
        {
            await JS.InvokeVoidAsync("requestNotificationPermission");
            await JS.InvokeVoidAsync("showNotification", title, message);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
    }


    private async void BroadcastSelf(string name, string message, string toSpec)
    {
        Console.WriteLine("BroadcastSelf burning");
        await daprClient.SaveStateAsync(DAPR_STATE_STORE, _username + "_recent_users", _recentUsers);
        _specoficMessages = await daprClient.GetStateAsync<List<Message>>(DAPR_STATE_STORE, name + "_spec_" + toSpec);

        if (_specoficMessages == null)
        {
            _specoficMessages = new List<Message>();
        }
        //根据_hubConnection.On<string, string>("Broadcast", BroadcastMessage);有相应的name
        if (message.Contains("wwwroot/files/img/"))
        {
            message = message.Replace("wwwroot/", "");
            Console.WriteLine("这个是图片" + message);
        }
        else if (message.Contains("wwwroot/files/file/"))
        {
            message = message.Replace("wwwroot/", "");
            Console.WriteLine("这个是文件" + message);
        }
        var result = _recentUsers.Find(recentUser => recentUser.Username == toSpec);
        if (result == null)
        {
            RecentUser recentUser = new RecentUser(specific_user, 0, Path.GetFileName(message));
            _recentUsers.Add(recentUser);
        }
        else
        {
            //更新最新的消息
            foreach (var recent_user in _recentUsers)
            {
                if (recent_user.Username == specific_user)
                {
                    recent_user.LatestMessage = Path.GetFileName(message);
                }
            }

        }
        var specific_message = new Message(name, message, true);
        _specoficMessages.Add(specific_message);
        //当前用户和来源用户作为键
        await daprClient.SaveStateAsync(DAPR_STATE_STORE, name + "_spec_" + toSpec, _specoficMessages);
        scroll_id = "specificChat";  
        StateHasChanged();
    }


    //会调用很多次
    private async void BroadcastMessage(string name, string message)
    {
        Console.WriteLine("_username:" + _username);
        Console.WriteLine("name is " + name);
        bool isMine = name.Equals(_username, StringComparison.OrdinalIgnoreCase);
        string[] split_arr = message.Split("@");
        string from_user = split_arr[split_arr.Length - 1];
        var isToSpecific = await daprClient.GetStateAsync<Boolean>(DAPR_STATE_STORE, from_user + "_to_" + name);
        Console.WriteLine("isToSpecific" + from_user + name + isToSpecific);
        message = "";
        for (var i = 0; i < split_arr.Length - 1; i++)
        {
            message += split_arr[i];
        }
        if (isToSpecific)
        {
            @* _isSpecific = true; *@
            _recentUsers = await daprClient.GetStateAsync<List<RecentUser>>(DAPR_STATE_STORE, name + "_recent_users");
            if (_recentUsers == null)
            {
                _recentUsers = new List<RecentUser>();
            }
            var recentUserContainFromUser = false;
            foreach (var recentUser in _recentUsers)
            {
                if ((recentUser.Username == from_user))
                {
                    Console.WriteLine("contain");
                    recentUserContainFromUser = true;
                }  
            }
            //如果不包含，添加
            if (!recentUserContainFromUser)
            {
                RecentUser recentUser = new RecentUser(from_user, 1, message);
                _recentUsers.Add(recentUser);
            }  
            //否则更新数量
            else
            {
				Console.WriteLine("specific_user11111." + specific_user);
                foreach (var recentUser in _recentUsers)
                {
                    if ((recentUser.Username == from_user))
                    {
                        if (specific_user != from_user)
                        {
                            recentUser.Counter = recentUser.Counter + 1;
							await ShowNotification(from_user, message);
                            Console.WriteLine("badge数量:" + recentUser.Counter);
                        } else
                        {
                            Console.WriteLine("如果是当前页面，数量就是0" + specific_user);
                            recentUser.Counter = 0;
                        }
                        Console.WriteLine(message);
                        if (message.Contains("wwwroot/files/")){
                           recentUser.LatestMessage = Path.GetFileName(message);
                        }
                    }
                }
    
            }
            //保存_recentUsers
            await daprClient.SaveStateAsync(DAPR_STATE_STORE, name + "_recent_users", _recentUsers);

			//这里要指定specific_user，否则拿不到所有的消息
            //如果切换到非当前页面，就会报错，果断不用这种方案。
            @* await JS.InvokeVoidAsync(
                "playNotificationAudio", notificationAudio); *@
            _specoficMessages = await daprClient.GetStateAsync<List<Message>>(DAPR_STATE_STORE, _username + "_spec_" + from_user);

            if (_specoficMessages == null) {
                _specoficMessages = new List<Message>();
            }
            //根据_hubConnection.On<string, string>("Broadcast", BroadcastMessage);有相应的name
            if (message.Contains("wwwroot/files/img/"))
            {
                message = message.Replace("wwwroot/", "");
                Console.WriteLine("这个是图片" + message);
            }
            else if (message.Contains("wwwroot/files/file/"))
            {
                message = message.Replace("wwwroot/", "");
                Console.WriteLine("这个是文件" + message);
            }
            var specific_message = new Message(from_user, message, false);
            _specoficMessages.Add(specific_message);
            //当前用户和来源用户作为键
            await daprClient.SaveStateAsync(DAPR_STATE_STORE, _username + "_spec_" + from_user, _specoficMessages);
            //设置specific是false
            await daprClient.SaveStateAsync(DAPR_STATE_STORE, from_user + "_to_" + name, false);
        } else {
            //如果是图片
            if (message.Contains("wwwroot/files/img/"))
            {
                message = message.Replace("wwwroot/", "");
                _latestMessage = message.Replace("files/img/", "");

                Console.WriteLine("这个是图片" + message);
            }
            else if (message.Contains("wwwroot/files/file/"))
            {
                message = message.Replace("wwwroot/", "");
                _latestMessage = message.Replace("files/file/", "");
                Console.WriteLine("这个是文件" + message);
            }else
            {
                _latestMessage = message;
            }
            Console.WriteLine(message);


            var new_message = new Message(name, message, isMine);
            if (_username != from_user)
            {
                //await ShowNotification(name, message);
                /*await JS.InvokeVoidAsync(
                    "playNotificationAudio", notificationAudio);*/

            }
            _messages.Add(new_message);
            await daprClient.SaveStateAsync(DAPR_STATE_STORE, _username, _messages);
            scroll_id = "hallChat";
        }
        Console.WriteLine("isSpecific" + _isSpecific);
        // Inform blazor the UI needs updating
        StateHasChanged();
    }

    private void SendMail(string content, string email)
    {
        MailMessage message = new();

        //设置发件人,发件人需要与设置的邮件发送服务器的邮箱一致
        MailAddress fromAddr = new("2250911301@qq.com");
        message.From = fromAddr;
        //设置收件人,可添加多个,添加方法与下面的一样
        message.To.Add(email);
        //设置抄送人
        // message.CC.Add("1592035782@qq.com");
        //设置邮件标题
        message.Subject = "打卡通知";
        //设置邮件内容
        message.Body = content;
        //设置邮件发送服务器,服务器根据你使用的邮箱而不同,可以到相应的邮箱管理后台查看
        SmtpClient client = new SmtpClient("smtp.qq.com", 25);
        //设置发送人的邮箱账号和授权码
        client.Credentials = new NetworkCredential("2250911301@qq.com", "gideydwxiwmudjji");

        //启用ssl,也就是安全发送
        client.EnableSsl = true;
        //发送邮件
        client.Send(message);
    }

    private async Task DisconnectAsync()
    {
        if (_isChatting)
        {
            Console.WriteLine(_username + "断开连接");
            await SendAsync($"[Notice] {_username} 离开聊天室.");

            await _hubConnection.StopAsync();
            await _hubConnection.DisposeAsync();

            _hubConnection = null;
            await localStorage.RemoveItemAsync("chat_username");
            _recentUsers = new List<RecentUser>();
            _isChatting = false;
            //删除用户，重新保存
            _users.Remove(_username);
            await daprClient.SaveStateAsync(DAPR_STATE_STORE, USERS_KEY, _users);
            if (timer != null)
            {
                timer.Dispose();
                timer = null;
            }
        }
    }
    private async Task backUserList() {
        messagelistStyle = "messagelistHide";
        userListStyle = "userListShow";

    }
    private async Task DisconnectSpecificAsync()
    {
        Console.WriteLine("断开链接");
    }

    private async Task SendAsync(string message)
    {

        // Use a regular expression to check if the message contains any explicit language or inappropriate content
        // if (Regex.IsMatch(message, @"\b(色情|黄色|赌博|毒品|暴力|恐怖)\b", RegexOptions.IgnoreCase))
        // {
        //     Console.WriteLine("Message contains inappropriate content");
        //     return;
        // }
        Console.WriteLine(message);
        if (_isChatting && !string.IsNullOrWhiteSpace(message))
        {
            Console.WriteLine("SendAsync 究竟谁发起的聊天:" + _username);
            //涉及到考勤发邮件处理
            if (message.Contains("合计出勤时间"))
            {
                SendMail(message, "2250911301@qq.com");
            }
            await _hubConnection.SendAsync("Broadcast", _username, message + "@" + _username);
            _newMessage = string.Empty;
        }
    }

    private async void startChatHall()
    {
        messagelistStyle = "messagelistShow";
        userListStyle = "userListHide";
        _isSpecific = false;
        specific_user = String.Empty;
        scroll_id = "hallChat";
        StateHasChanged();
    }

    private async Task StartChatWithSpecificUser(String user, String newMessage)
    {
        messagelistStyle = "messagelistShow";
        userListStyle = "userListHide";
        if (user == _username) {
            Console.WriteLine("暂时不支持给自己发送消息");
            return;
        }
        _isSpecific = true;
        specific_user = user;
        _specoficMessages = await daprClient.GetStateAsync<List<Message>>(DAPR_STATE_STORE, _username + "_spec_" + specific_user);
        if (_specoficMessages == null) {
            _specoficMessages = new List<Message>();
        }
        //点击直接计数请0
        if (newMessage == "")
        {
            _recentUsers = await daprClient.GetStateAsync<List<RecentUser>>(DAPR_STATE_STORE, _username + "_recent_users");
            if (_recentUsers == null)
            {
                _recentUsers = new List<RecentUser>();
            }
            //否则更新数量为0
            else
            {
                foreach (var recentUser in _recentUsers)
                {
                    if ((recentUser.Username == user))
                    {
                        recentUser.Counter = recentUser.Counter = 0;
                        Console.WriteLine("badge数量:" + recentUser.Counter);
                    }
                }

            }
            //保存_recentUsers
            await daprClient.SaveStateAsync(DAPR_STATE_STORE, _username + "_recent_users", _recentUsers);
        }
        else
        {
            Console.WriteLine("why not here"  + newMessage);
            var result = _recentUsers.Find(recentUser => recentUser.Username == user);
            if (result == null)
            {
                RecentUser recentUser = new RecentUser(user, 0, newMessage);
                _recentUsers.Add(recentUser);
            } else {
                //更新最新的消息
                foreach (var recent_user in _recentUsers) {
                    if (recent_user.Username == user) {
                        recent_user.LatestMessage = newMessage;
                    }
                }

            }				 
            await daprClient.SaveStateAsync(DAPR_STATE_STORE, _username + "_recent_users", _recentUsers);
            var specific_message = new Message(_username, newMessage, true);
            _specoficMessages.Add(specific_message);

            await daprClient.SaveStateAsync(DAPR_STATE_STORE, _username + "_spec_" + user, _specoficMessages);
            newMessage += "@" + _username;

            await _hubConnection.SendAsync("BroadcastToSpecificUser", user, newMessage);
            _newMessage = string.Empty;
        }
        scroll_id = "specificChat";  
        StateHasChanged();
    }

    //function CheckEnterKey(event) {
    /*if (event.keyCode === 13) { // 13 is the key code for enter
        DotNet.invokeMethodAsync('MyApp', 'OnEnterKeyPressed'); // invoke a C# method named "OnEnterKeyPressed" in the "MyApp" namespace
    }
    }*/
    private async void WatchInputValue(KeyboardEventArgs e) {
        Console.WriteLine("is shift pressed" + e.ShiftKey);
        if (e.ShiftKey && e.Key == "Enter")
        {
            Console.WriteLine("message是" + _newMessage);
            _newMessage += "\n";
        }
        else if (e.Code == "Enter" || e.Code == "NumpadEnter")
        {
            Console.WriteLine("Enter" + _newMessage);
            if (specific_user == String.Empty || specific_user == "")
            {
                await SendAsync(_newMessage);
            } else
            {
                await StartChatWithSpecificUser(specific_user, _newMessage);
            }
        }

	}

    //可用来监控页面是否关闭
	void IDisposable.Dispose()
    {
		specific_user = String.Empty;
		if (timer != null)
		{
		    timer.Dispose();
		    timer = null;
		}
        Console.WriteLine("Disposing.");
    }

}